﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkedList
{
    public class LinkedList<T> : ICollection<T>
    {
        #region Inre klassen Node<T>
        private class Node<T>
        {
            public T value = default(T);
            public Node<T> next;
            public Node<T> previous;

            public Node()
            {
                next = previous = null;
            }

            public Node(T value)
            {
                this.value = value;
            }

            ~Node()
            {               
            }
        }
        #endregion

        private Node<T> head = null;
        private Node<T> tail = null;
        private int size = 0;

        public bool isEmpty()
        {
            return head == null;
        }

        public T First()
        {
            if (head == null)
            {
                throw new Exception("LinkedList.Front: Empty list");
            }

            else return head.value;
        }

        public T Last()
        {
            if (head == null)
            {
                throw new Exception("LinkedList.Front: Empty list");
            }

            else return tail.value;
        }

        public int CountNodes()
        {
            Node<T> node = head;
            int count = 0;

            while(node != null)
            {
                count++;
                node = node.next;
            }

            return count;
        }

        public void AddFirst(T item)
        {
            Node<T> n = new Node<T>(item);
            if(this.isEmpty())
            {  
                head = n;
                tail = n;
            }

            else
            {
                head.previous = n;
                n.next = head;
                head = n; 
            }

        }

        public void AddLast(T item)
        {
            Node<T> n = new Node<T>(item);

            if(this.isEmpty())
            {
                head = n;
                tail = n;
            }

            else
            {
                tail.next = n;
                n.previous = tail;
                tail = n;
            }
        }

        public T Find(T item)
        {
            foreach (var v in this )
            {
                if(item.Equals(v))
                {
                    return v;
                }
            }

            throw new Exception("LinkedList.Find: Did not find node");
        }

        public void RemoveFirst()
        {
            head.next.previous = null;
            head = head.next;
        }

        public void RemoveLast()
        {
            tail.previous.next = null;
            tail = tail.previous;
        }


        #region ICollection
        public void Add(T item)
        {
            throw new NotImplementedException();
        }

        public void Clear()
        {
            head = null;
            tail = null;
        }
        public bool Contains(T item)
        {
            foreach (var v in this)
            {
                if(item.Equals(v))
                {
                    return true;
                }
            }
            return false;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsReadOnly
        {
            get { throw new NotImplementedException(); }
        }

        public bool Remove(T item)
        {
            if(head == null)
            {
                return false;
            }

            if(item.Equals(head.value))
            {
                head.next.previous = null;
                head = head.next;
                return true;
            }

            if (item.Equals(tail.value))
            {
                tail.previous.next = null;
                tail = tail.previous;
                return true;
            }

            else
            {
                Node<T> nodeBefore = head;
                Node<T> node = head.next;

                while(node != null)
                {
                    if(item.Equals(node.value))
                    {
                        nodeBefore.next = node.next;
                        node.next.previous = nodeBefore;
                        return true;
                    }

                    nodeBefore = nodeBefore.next;
                    node = node.next;
                }
            }

            return false;
        }


        public IEnumerator<T> GetEnumerator()
        {
            Node<T> n = head;

            while (n != null)
            {
                yield return n.value;
                n = n.next;
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        } 

        #endregion

    }
    
   
}
